﻿using System.Collections.Generic;
using Engine;
using Game;
using Mekiasm.Common;
using Mekiasm.ElectricElement;
using TemplatesDatabase;
namespace Mekiasm
{
    public class TransmitMachine : ItemCube
    {
        public static int Index;
        public static Dictionary<Point3, MutiBlockCheck.TranmitResult> saves = new Dictionary<Point3, MutiBlockCheck.TranmitResult>();
        public static int TransmitUse = 5 * 1024;//5 * 1024;

        public static MutiBlockCheck MutiBlockCheck = new MutiBlockCheck();
        public static bool AllowTransmit = true;
        public static bool IsExec = false;
        public TransmitMachine() : base("传送机")
        {
            
        }
        public override MekBlock.DeviceType GetDeviceType()
        {
            return MekBlock.DeviceType.Electric;
        }
        public override int GetFaceTextureSlot(int face, int value)
        {
            return 64;
        }
        public override bool OnUse(Ray3 aim, ComponentMiner componentMiner, TerrainRaycastResult? raycast)
        {
            return false;
        }
        public override bool IsCollidable(int value)
        {
            return true;
        }
        public override void OnCollide(CellFace cellFace, float velocity, ComponentBody componentBody)
        {
            if (!AllowTransmit || cellFace.Face != 4) return;
            if (saves.TryGetValue(cellFace.Point, out MutiBlockCheck.TranmitResult tranmitResult))
            {
                if (tranmitResult.Connected)
                {
                    ComponentTransmitMachine mcomponent = ILibrary.Project.FindSubsystem<SubsystemBlockEntities>().GetBlockEntity(cellFace.X, cellFace.Y, cellFace.Z).Entity.FindComponent<ComponentTransmitMachine>(true);
                    if (mcomponent.Power >= TransmitUse && AllowTransmit)
                    {
                        mcomponent.Power -= TransmitUse;
                        AllowTransmit = false;
                        IsExec = false;
                        Vector3 vector3 = new Vector3(tranmitResult.Connection);
                        SubsystemMekBlockBehavior.CacheTasks.Add(() =>
                        {
                            if (!IsExec && ILibrary.SubsystemTime.PeriodicGameTimeEvent(2.0, 0.0))
                            {
                                if (tranmitResult.directionIsX) componentBody.Position = new Vector3(tranmitResult.Connection.X + 0.5f, tranmitResult.Connection.Y + 1, tranmitResult.Connection.Z);
                                else componentBody.Position = new Vector3(tranmitResult.Connection.X, tranmitResult.Connection.Y + 1, tranmitResult.Connection.Z + 0.5f);
                                IsExec = true;
                            }
                            float f = Vector3.DistanceSquared(componentBody.Position, vector3);
                            if (f > 4f && IsExec)
                            {
                                AllowTransmit = true; return true;
                            }
                            return false;
                        });
                    }
                }
            }
        }
        public override void OnBlockAdded(SubsystemBlockBehavior blockBehavior, int value, int oldValue, int x, int y, int z)
        {
            Point3 point3 = new Point3(x, y, z);
            if (CheckTransmitDoor(point3))
            {
                ILibrary.AddBaseEnergyEntity(DisplayName, x, y, z, new List<ComponentEnergyMachine.Slot>() { //格子初始化
                new ComponentEnergyMachine.Slot(){ FuelCapacity=40960 }
            }, ILibrary.GetRotetedConfig(value, new MachineFaceConfig[] {
                new MachineFaceConfig(MekBlock.MachineMode.IN,MekBlock.DeviceType.Electric),
                new MachineFaceConfig(MekBlock.MachineMode.IN,MekBlock.DeviceType.Electric),
                new MachineFaceConfig(MekBlock.MachineMode.IN,MekBlock.DeviceType.Electric),
                new MachineFaceConfig(MekBlock.MachineMode.IN,MekBlock.DeviceType.Electric),
                new MachineFaceConfig(MekBlock.MachineMode.IN,MekBlock.DeviceType.Electric),
                new MachineFaceConfig(MekBlock.MachineMode.IN,MekBlock.DeviceType.Electric)
            }));
                ElectricSystem.Add(new TransmitMachineElement(x, y, z));
            }
            else
            {
                if (saves.TryGetValue(point3, out MutiBlockCheck.TranmitResult tranmitResult))
                {
                    SetInsideBlocks(tranmitResult.insidePoints, 0);
                }
            }
        }
        public override void OnBlockGenerated(int value, int x, int y, int z, bool isLoaded)
        {
            Point3 point3 = new Point3(x, y, z);
            if (saves.TryGetValue(point3, out MutiBlockCheck.TranmitResult tranmitResult))
            {
                ElectricSystem.Add(new TransmitMachineElement(x, y, z));
            }
        }
        public override void OnBlockRemoved(SubsystemBlockBehavior blockBehavior, int value, int newValue, int x, int y, int z)
        {
            Point3 point3 = new Point3(x, y, z);
            if (!CheckTransmitDoor(point3) && saves.TryGetValue(point3, out MutiBlockCheck.TranmitResult tranmitResult))
            {
                SetInsideBlocks(tranmitResult.insidePoints, 0);
            }
            ElectricSystem.Remove(point3);
            ILibrary.RemoveBlockEntity(x, y, z);
        }
        public override bool OnInteract(SubsystemBlockBehavior blockBehavior, TerrainRaycastResult raycastResult, ComponentMiner componentMiner)
        {
            if (saves.TryGetValue(raycastResult.CellFace.Point, out MutiBlockCheck.TranmitResult tranmitResult))
            {
                ComponentTransmitMachine mcomponent = blockBehavior.Project.FindSubsystem<SubsystemBlockEntities>().GetBlockEntity(raycastResult.CellFace.X, raycastResult.CellFace.Y, raycastResult.CellFace.Z).Entity.FindComponent<ComponentTransmitMachine>(true);
                componentMiner.ComponentPlayer.ComponentGui.ModalPanelWidget = new TransmitWidget(mcomponent, tranmitResult, componentMiner);
                return true;
            }
            return false;
        }
        public override bool IsInteractive(SubsystemTerrain subsystemTerrain, int value)
        {
            return true;
        }
        public static bool CheckBlock(int v1, int v2)
        {
            if (Terrain.ExtractContents(v1) == Terrain.ExtractContents(v2) && Terrain.ExtractData(v1) == Terrain.ExtractData(v2)) return true;
            return false;
        }
        public static void SetInsideBlocks(List<Point3> points, int value)
        {
            foreach (Point3 point3 in points)
            {
                ILibrary.SubsystemTerrain.ChangeCell(point3.X, point3.Y, point3.Z, value);
            }
        }
        public static bool CheckTransmitDoor(Point3 start)
        {

            MutiBlockCheck.TranmitResult tranmitResult = MutiBlockCheck.checkTransmit(ILibrary.SubsystemTerrain, start, new List<MutiBlockCheck.AcceptBlock>() { new MutiBlockCheck.AcceptBlock(TransmitMachine.Index, CheckBlock), new MutiBlockCheck.AcceptBlock(TransmitBox.Index, CheckBlock) }, TransmitItem.Index);
            if (tranmitResult.finished)
            {
                //检查中心是否为空气
                foreach (Point3 point3 in tranmitResult.insidePoints)
                {
                    int v = ILibrary.SubsystemTerrain.Terrain.GetCellContents(point3.X, point3.Y, point3.Z);
                    int id = Terrain.ExtractContents(v);
                    int data = Terrain.ExtractData(v);
                    if (ILibrary.GetBasicValue(v) != 0 && ILibrary.GetBasicValue(v) != TransmitItem.Index) return false;
                }
                if (!saves.ContainsKey(start))
                {
                    saves.Add(start, tranmitResult);
                }
            }
            return tranmitResult.finished;
        }
        public static void Load(ValuesDictionary k1)
        {
            saves.Clear();
            foreach (ValuesDictionary t in k1.Values)
            {
                MutiBlockCheck.TranmitResult tranmitResult = new MutiBlockCheck.TranmitResult();
                Point3 key = t.GetValue<Point3>("p");
                tranmitResult.bottom = t.GetValue<Point3>("bottom");
                tranmitResult.Connected = t.GetValue<bool>("Connected");
                tranmitResult.top = t.GetValue<Point3>("top");
                tranmitResult.Connection = t.GetValue<Point3>("Connection");
                tranmitResult.directionIsX = t.GetValue<bool>("directionIsX");
                tranmitResult.insidePoints = new List<Point3>();
                foreach (Point3 point3 in t.GetValue<ValuesDictionary>("ps").Values)
                {
                    tranmitResult.insidePoints.Add(point3);
                }
                saves.Add(key, tranmitResult);
            }
        }
        public static ValuesDictionary Save()
        {
            ValuesDictionary k0 = new ValuesDictionary();
            int c = 0;
            foreach (var t in saves)
            {
                ValuesDictionary k1 = new ValuesDictionary();
                k1.SetValue("p", t.Key);
                k1.SetValue("bottom", t.Value.bottom);
                k1.SetValue("top", t.Value.top);
                k1.SetValue("Connection", t.Value.Connection);
                k1.SetValue("Connected", t.Value.Connected);
                k1.SetValue("directionIsX", t.Value.directionIsX);
                ValuesDictionary k2 = new ValuesDictionary();
                for (int i = 0; i < t.Value.insidePoints.Count; i++)
                {
                    k2.SetValue(i.ToString(), t.Value.insidePoints[i]);
                }
                k1.SetValue("ps", k2);
                k0.SetValue(c++.ToString(), k1);
            }
            return k0;
        }
    }
}
